#include "Socket.hpp"
#include "log.hpp"
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstring>
#include <cstdlib>
#include <iostream>

static const int FD_SET_SIZE = 1024;

class Select
{
public:
    Select(uint16_t port) : _port(port)
    {
        for (int i = 0; i < FD_SET_SIZE; ++i)
        {
            _fd_array[i] = -1;
        }
    }

    void Init()
    {
        _sock.Socket();
        _sock.Bind(_port);
        _sock.Listen();

        _fd_array[0] = _sock.GetListenSock();
    }

    void Start()
    {
        for (;;)
        {
            // 准备好位图
            fd_set r_event;
            FD_ZERO(&r_event);
            int max_fd = 0;
            for (int i = 0; i < FD_SET_SIZE; ++i)
            {
                if (_fd_array[i] == -1)
                    continue;
                else
                {
                    FD_SET(_fd_array[i], &r_event);
                    if (_fd_array[i] > max_fd)
                        max_fd = _fd_array[i];
                }
            }
            struct timeval timeout = {3, 0};

            int n = select(max_fd + 1, &r_event, nullptr, nullptr, nullptr);
            switch (n)
            {
            case -1:
                lg(Error, "select error: code:%d msg:%s", errno, strerror(errno));
                exit(-1);
                break;
            case 0:
                std::cout << "超时，进行下一次等待" << std::endl;
                break;
            default:
                std::cout << "有" << n << "个文件描述符处于就绪状态" << std::endl;
                Dispatcher(&r_event);
                break;
            }
        }
    }

    void Accepter() // 链接管理器
    {
        std::string clientip;
        uint16_t clientport;
        int sock = _sock.Accept(clientip, clientport);
        if (sock < 0) return;
            lg(Info, "accept success, %s: %d, sock fd: %d", clientip.c_str(), clientport, sock);

        int pos = 1;
        for (; pos < FD_SET_SIZE; ++pos)
        {
            if (_fd_array[pos] != -1)
                continue;

            _fd_array[pos] = sock;
            break;
        }
        // 满了
        if (pos == FD_SET_SIZE)
        {
            lg(Warning, "_fd_array full");
            close(sock);
        }
    }

    void Recver(int fd, int pos)
    {
        char buffer[128];
        std::string res = "get mseeage, fd: ";
        res += std::to_string(fd);
        res += " msg: ";
        
        int n = recv(fd, buffer, sizeof(buffer) - 1, 0);

        if (n < 0)
        {
            lg(Error, "recv error, fd:%d, code:%d, msg:%s", fd, errno, strerror(errno));
            _fd_array[pos] = -1;
            close(fd);
            return;
        }
        else if (0 == n)
        {
            // 对方写端关闭,也有可能是刚好读完
            lg(Debug, "close file, fd:%d", fd);
            _fd_array[pos] = -1;
            close(fd);
            return;
        }
        else
        {
            buffer[n] = 0;
            res += buffer;
        }
        
        std::cout << res << std::endl;
    }

    // 负责调度
    void Dispatcher(fd_set *p_r_event)
    {
        for (int i = 0; i < FD_SET_SIZE; ++i)
        {
            if (_fd_array[i] == -1)
                continue;

            if (FD_ISSET(_fd_array[i], p_r_event))
            {
                if (_fd_array[i] == _sock.GetListenSock())
                    Accepter();
                else
                    Recver(_fd_array[i], i);
            }
        }
    }
    
    ~Select()
    {
        _sock.Close();
    }
private:
    Sock _sock;
    int _fd_array[FD_SET_SIZE];
    uint16_t _port;
};
